home *** CD-ROM | disk | FTP | other *** search
/ Resource Library: Multimedia / Resource Library: Multimedia.iso / maestro / source / timeline / file.c < prev    next >
Encoding:
Text File  |  1993-06-15  |  37.7 KB  |  923 lines

  1. /*
  2.  * Copyright (c) 1990, 1991 Stanford University
  3.  *
  4.  * Permission to use, copy, modify, and distribute this software and 
  5.  * its documentation for any purpose is hereby granted without fee, provided
  6.  * that (i) the above copyright notices and this permission notice appear in
  7.  * all copies of the software and related documentation, and (ii) the name
  8.  * Stanford may not be used in any advertising or publicity relating to
  9.  * the software without the specific, prior written permission of
  10.  * Stanford.
  11.  * 
  12.  * THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND, 
  13.  * EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY 
  14.  * WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.  
  15.  *
  16.  * IN NO EVENT SHALL STANFORD BE LIABLE FOR ANY SPECIAL, INCIDENTAL,
  17.  * INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND, OR ANY DAMAGES
  18.  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER OR NOT
  19.  * ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF LIABILITY,
  20.  * ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
  21.  * SOFTWARE.
  22.  */
  23.  
  24. /* $Header: /Source/Media/collab/TimeLine/RCS/file.c,v 1.15 92/10/30 16:21:27 drapeau Exp $ */
  25. /* $Log:    file.c,v $
  26.  * Revision 1.15  92/10/30  16:21:27  drapeau
  27.  * Fixed an error in the OpenHandler() function.  Simple, silly, common C
  28.  * mistake: used "=" in the test of an if statement instead of the proper
  29.  * "==", when testing for whether synchronization hints are available.
  30.  * 
  31.  * Revision 1.14  92/10/02  15:00:32  drapeau
  32.  * Minor change made to OpenHandler().  It now corrects an error that failed to
  33.  * reset the playback head to the beginning of a newly-opened document.
  34.  * 
  35.  * Revision 1.13  92/10/01  14:43:19  drapeau
  36.  * Modified OpenHandler() and SaveHandler() to read and write additional
  37.  * synchronization hints information.  If a TimeLine document does not
  38.  * have any synchronization hints available, then when it is saved a new
  39.  * field will be added to the TimeLine document indicating that there is no
  40.  * synchronization information available; if the hints are available,
  41.  * SaveHandler() will indicate the presence of these hints.
  42.  * The OpenHandler() routine will look for this field in a TimeLine document
  43.  * if it is a Version 2 document, and will then determine if the document
  44.  * has sync hints available for it.
  45.  * 
  46.  * Revision 1.12  92/09/24  17:03:21  drapeau
  47.  * The OpenHandler() and SaveHandler() functions were modified to support
  48.  * documents with synchronization information, as well as older style
  49.  * documents that do not contain "sync hints".  The new document style differs
  50.  * from the old in two ways:
  51.  * 1) The header is slightly different (new header is
  52.  *    "#TimeLine Edit Document, Version 2#");
  53.  * 2) There is an extra line of information for each note.  This extra line
  54.  *    denotes an estimate of the time (in milliseconds) it will take to
  55.  *    prepare the note for performance.
  56.  * Both handlers had to be modified to read and write this additional
  57.  * information.  In addition, when OpenHandler() reads a new-style document with
  58.  * sync hints, it sets a flag for the current document indication that sync
  59.  * hints are available for use.
  60.  * Other changes are cosmetic, to improve readability and ANSI compliance.
  61.  * Also, code that makes reference to the TimeLine document header (e.g., calls
  62.  * to the Browse functions) have been changed to accommodate the new document
  63.  * format.
  64.  * 
  65.  * Revision 1.11  92/09/12  19:17:11  drapeau
  66.  * Slight modification to make code more portable: the order of include files
  67.  * was changed to help insure that typedefs like "dev_t" are picked up before
  68.  * the include file "<sys/stat.h>" is loaded.  To insure this, "main.h" is now
  69.  * included before "<sys/stat.h>".
  70.  * 
  71.  * Revision 1.10  92/05/29  14:41:42  drapeau
  72.  * Modified code to track new name of the MAEstro "Selection" structure;
  73.  * it is now named "MAESelection".
  74.  * 
  75.  * Revision 1.0  91/09/30  16:56:15  chua
  76.  * Update to version 1.0
  77.  * 
  78.  * Deleted an unused variable (found) in OpenHandler.
  79.  * 
  80.  * Both FreeInstrumentList and ClearAllNotes take tlFrame as the parameter, instead of
  81.  * tlFrame->instHead.
  82.  * 
  83.  * Revision 0.85  91/09/25  13:48:01  chua
  84.  * In CloseHandler, if there are multiple TimeLine frames open, destroy the current frame.
  85.  * Else, just close the document and reset the filename to 'untitled'.
  86.  * 
  87.  * Revision 0.84  91/09/23  17:10:26  chua
  88.  * Change the selectedInstrument element to noteInstrument, as the latter is
  89.  * now used to indicate which instrument has the currently selected note.
  90.  * 
  91.  * Revision 0.83  91/09/19  17:28:46  chua
  92.  * Make sure that variables are initialized properly.  Change formatting slightly,
  93.  * so that (if, for, while) statements with only one statement in them will not have
  94.  * braces.
  95.  * 
  96.  * Revision 0.82  91/09/17  18:10:12  chua
  97.  * In SaveHandler, correct an error when counting the number of applications
  98.  * that have notes.
  99.  * 
  100.  * Revision 0.81  91/09/17  17:15:30  chua
  101.  * In SaveHandler, when writing the names of the applications, check to see that the
  102.  * apps have notes first.
  103.  * 
  104.  * Revision 0.80  91/09/17  17:13:14  chua
  105.  * Changed the name of the structure Region to tlRegion, to avoid clashes with 
  106.  * definitions in some X library.
  107.  * 
  108.  * In OpenHandler, first read the applications required by the file and create an
  109.  * instrument list using these applications.  Call OpenAppsInitialize to assign port
  110.  *  numbers to the applications (if they are open).
  111.  * 
  112.  * In SaveHandler, only save the applications which have notes in them.
  113.  * 
  114.  * Revision 0.79  91/09/16  14:41:17  chua
  115.  * Include the Browse.h file.
  116.  * In calls to InstrumentNew, add a new parameter at the end.  This parameter indicates the
  117.  * application name (used for applications which are not currently open).  
  118.  * 
  119.  * Revision 0.78  91/09/09  14:56:39  chua
  120.  * Removed the struct stat stbuf declaration in line 321.
  121.  * 
  122.  * Revision 0.77  91/09/06  17:31:58  chua
  123.  * In CheckforUntitled, cast rindex to char * (first line).
  124.  * 
  125.  * Revision 0.76  91/09/04  15:09:11  chua
  126.  * Replaced the calls to notice_prompt with a call to AlertMessage.
  127.  * 
  128.  * Revision 0.75  91/08/26  14:21:16  chua
  129.  * When saving a file, keep track of all the applications that are currently open,
  130.  * instead of just saving those applications that have notes in them.
  131.  * 
  132.  * Revision 0.74  91/08/22  15:58:58  chua
  133.  * Made some changes to both OpenHandler and SaveHandler when checking if the file being
  134.  * opened is a TimeLine Edit file.
  135.  * 
  136.  * Revision 0.73  91/08/22  15:33:49  chua
  137.  * Shortened the dividers ("****....**") in the document format.
  138.  * 
  139.  * Revision 0.72  91/08/22  15:01:26  chua
  140.  * Deleted the FileError routine as error checking is now performed by the Browser.
  141.  * 
  142.  * Changed the TimeLine document format so that there are now more spaces and markings
  143.  * to clearly denote different regions.
  144.  * 
  145.  * Revision 0.71  91/08/16  16:58:11  chua
  146.  * Removed some extra variables which are not used.  Also, in the calls to Browse,
  147.  * replace OPENPANEL_OPEN and OPENPANEL_SAVE by BrowseOpen and BrowseSave respectively.
  148.  * 
  149.  * In the file format, add spacing between information for region, pause and notes.
  150.  * 
  151.  * Revision 0.70  91/08/12  16:12:29  chua
  152.  * Changed the comment heading.
  153.  * 
  154.  * Revision 0.69  91/08/12  16:08:20  chua
  155.  * *** empty log message ***
  156.  * 
  157.  * Revision 0.68  91/08/12  16:02:48  chua
  158.  * Added two new routines, SaveAsFileHandler and CloseHandler.
  159.  * The SaveAsFileHandler will bring up the open/save panel for 
  160.  * the user to select or type a filename.
  161.  * The CloseHandler will close the current file and reset the
  162.  * filename to 'untitled'. The canvas will also be cleared.
  163.  *
  164.  * In the SaveHandler, the open/save panel will not be brought up
  165.  * unless the filename is 'untitled'.
  166.  * 
  167.  * Revision 0.67  91/08/09  15:12:32  chua
  168.  * Changed the name of InfoHandler to AboutHandler.
  169.  * 
  170.  * Revision 0.66  91/08/08  14:21:35  chua
  171.  * In the OpenFileHandler and SaveFileHandler, the call to Browse takes different parameters.
  172.  * 
  173.  * In OpenHandler, if an application in the file is not currently open, instead of just
  174.  * printing an error message and not allowing the user to open the file, create an instrument
  175.  * node for the application and display it as well.  However, make the instrument
  176.  * permanently muted.
  177.  * 
  178.  * Revision 0.65  91/08/05  16:53:04  chua
  179.  * Deleted the RepaintCanvas routine, as it is no longer necessary.  In places where it
  180.  * is called, just call the ScrollToFirstQuarter routine, which will do the necessary
  181.  * repaint as well.
  182.  * 
  183.  * Revision 0.64  91/07/30  11:21:25  chua
  184.  * Incorporated the file browser.  The menu handlers for the open and save buttons
  185.  * will call the Browse function in the Browse code.  This browse function will
  186.  * then call either the OpenHandler or SaveHandler which will return a 0 if it
  187.  * likes the pathname given by the browser, or 1 otherwise.
  188.  * 
  189.  * Revision 0.63  91/07/26  17:24:22  chua
  190.  * In the OpenHandler and SaveHandler, where there is a 'return NULL', do a 
  191.  * 'return item' instead.  Apparently, returning a NULL will cause Errors.
  192.  * 
  193.  * Also include code to write and read information about annotated regions in the
  194.  * file.
  195.  * 
  196.  * Revision 0.62  91/07/24  10:33:11  chua
  197.  * In the OpenHandler and SaveHandler, include code for saving the pause marker information.
  198.  * 
  199.  * 
  200.  * Revision 0.61  91/07/17  16:31:26  chua
  201.  * Added two new functions, InfoHandler and CloseInfoPopup to open and close the
  202.  * Info popup window respectively.
  203.  * 
  204.  * Revision 0.60  91/07/09  16:57:48  chua
  205.  * In the QuitHandler procedure, move most of the code into the QuitNotify procedure
  206.  * in TimeLine.c
  207.  * 
  208.  * Revision 0.59  91/06/26  16:53:30  chua
  209.  * In the Error message which is printed in OpenHandler when one of the applications are not
  210.  * open, just add the line "The file cannot be opened".
  211.  * 
  212.  * Revision 0.58  91/06/25  17:15:05  chua
  213.  * Reformatted a comment line.
  214.  * 
  215.  * Revision 0.57  91/06/04  17:37:14  chua
  216.  * Added the copyright comments in the beginning of the file.
  217.  * 
  218.  * Revision 0.56  91/06/04  17:25:00  chua
  219.  * In the QuitHandler, if it is the Clipboard, do not destroy the frame, but simply make
  220.  * it not visible.
  221.  * 
  222.  * Destroy the clipboard if all Document windows have been destroyed.
  223.  * 
  224.  * Revision 0.55  91/06/04  10:42:22  chua
  225.  * Added a call to UpdateHeader whenever there is a change in the status of
  226.  * the current document (the change flag set to 1).
  227.  * 
  228.  * Revision 0.54  91/06/03  11:11:50  chua
  229.  * Make changes to accomodate multiple documents.  This involves identifying
  230.  * which is the current active window, that is, the one where the last mouse
  231.  * click was done.
  232.  * 
  233.  * Revision 0.53  91/05/30  12:07:44  chua
  234.  * Added an extra parameter in the call to InitNotesInfo.  The second parameter,
  235.  * deselect, indicates if the currently selected note is to be deselected.
  236.  * 
  237.  * Revision 0.52  91/05/29  14:31:40  chua
  238.  * In the LoadHandler, it is not necessary to call the ClearNoteInfoList function in lines
  239.  * 236-241.
  240.  * 
  241.  * Revision 0.51  91/05/28  12:09:40  chua
  242.  * *** empty log message ***
  243.  * 
  244.  * Revision 0.50  91/05/24  16:36:38  chua
  245.  * *** empty log message ***
  246.  * 
  247.  * Revision 0.49  91/05/23  17:38:53  chua
  248.  * *** empty log message ***
  249.  * 
  250.  * Revision 0.48  91/05/22  16:40:04  chua
  251.  * 
  252.  * 
  253.  * Revision 0.47  91/05/22  13:55:56  chua
  254.  * 
  255.  * 
  256.  * Revision 0.46  91/05/22  11:38:21  chua
  257.  * In the procedure TextfieldLoad, the parameters passed in the call to OpenHandler are
  258.  * tlFrame->changed to NULL, MENU_NOTIFY, so that pressing the return key after typing in the filename
  259.  * will activate the loading procedure.  The parameters were NULL, NULL before, because the
  260.  * Open procedure used to be a button notify procedure instead of a menu button handler.
  261.  * 
  262.  * Revision 0.45  91/05/17  16:57:47  chua
  263.  * *** empty log message ***
  264.  * 
  265.  * Revision 0.44  91/05/17  16:56:51  chua
  266.  * *** empty log message ***
  267.  * 
  268.  * Revision 0.43  91/05/16  15:19:34  chua
  269.  * Changed the names of Load and Save to OpenHandler and SaveHandler (since they are now menu button
  270.  * handlers).
  271.  * 
  272.  * Also added a new handler QuitHandler to this file (from TimeLine.c)
  273.  * 
  274.  * Revision 0.42  1991/04/24  00:57:45  chua
  275.  * The only tlFrame->change made here is in the Load procedure. There is no longer any need to check if
  276.  * (instrument->instInfo != NULL), since instInfo is now never NULL as the pop-up window will
  277.  * always be created whenever an instrument is created.
  278.  *
  279.  * Revision 0.41  1991/04/08  20:55:35  chua
  280.  * TlFrame->Changes are made in the Load procedure.  Before the loading of a file is done, the panel lists of all the
  281.  * pop-up windows that have been created are cleared.  After loading is done, the panel lists are then updated
  282.  * with the new notes information for each instrument.  This is done by calling the InitNotesInfo procedure
  283.  * in notesInfo.c for each instrument where the pop-up window has already been created.
  284.  *
  285.  * Revision 0.40  1991/04/01  01:46:54  chua
  286.  * This file contains the functions for loading and saving a TimeLine document (Load and Save).  There are also two
  287.  * smaller functions to check for Errors when opening or saving a file (FileError and CheckforUntitled).
  288.  * The text notify procedure for the filename textfield calls the Load procedure (notify procedure for the Load
  289.  * button).  That is, if the user types in a filename and hits return, it is equivalent to pressing the Load button
  290.  * after typing in the filename.
  291.  * */
  292.  
  293. static char filercsid[] = "$Header: /Source/Media/collab/TimeLine/RCS/file.c,v 1.15 92/10/30 16:21:27 drapeau Exp $";
  294.  
  295. #include "main.h"
  296. #include <errno.h>
  297. #include <sys/stat.h>
  298. #include <Browse.h>
  299.  
  300. /*
  301.  * Checks if the filename specified by the user is 'untitled'.  This is not allowed as it is the default used by the timeline if no filename
  302.  * has been specified.  A return value of 1 indicates that the filename is 'untitled' and the user should choose another.  Otherwise,
  303.  * a value of 0 is returned.
  304.  * Called by procedures Load and Save, both in file.c
  305.  */
  306. int CheckforUntitled(filename)
  307.      char *filename;
  308. {
  309.   char *tempfile;
  310.     
  311.   tempfile = (char *) rindex(filename, '/');                /* check if filename is 'untitled'.  If so, ask for another filename */
  312.   if (tempfile != NULL) 
  313.   {
  314.     if (strcmp(&tempfile[1], "untitled") == 0) 
  315.       return 1;
  316.   }  
  317.   else 
  318.   {
  319.     if (strcmp(filename, "untitled") == 0) 
  320.       return 1;
  321.   }
  322.   return 0;
  323. }
  324.  
  325. /*
  326.  * Menu handler for `DocumentMenu (Open)'.
  327.  * Brings up the file browser which allows the user to select a file to be opened.
  328.  */
  329. Menu_item OpenFileHandler(item, op)
  330.      Menu_item    item;
  331.      Menu_generate    op;
  332. {
  333.   TimeLine_window_objects * ip = (TimeLine_window_objects *) xv_get(item, XV_KEY_DATA, INSTANCE);
  334.  
  335.   switch (op) 
  336.   {
  337.    case MENU_DISPLAY:
  338.     break;
  339.    case MENU_DISPLAY_DONE:
  340.     break;
  341.    case MENU_NOTIFY:
  342.     Browse(NULL, BrowseOpen, (int) xv_get(ip->controls, PANEL_CLIENT_DATA), 
  343.        "#TimeLine Edit Document", "TimeLine Editor");
  344.     break;
  345.    case MENU_NOTIFY_DONE:
  346.     break;
  347.   }
  348.   return item;
  349. }
  350.  
  351. /*
  352.  * Menu handler for `DocumentMenu (Save)'.
  353.  * Brings up the file browser which allows the user to select a file to save the current TimeLine document into.
  354.  */
  355. Menu_item SaveFileHandler(Menu_item    item,
  356.               Menu_generate    op)
  357. {
  358.   TimeLineFramePtr tlFrame;
  359.   TimeLine_window_objects * ip = (TimeLine_window_objects *) xv_get(item, XV_KEY_DATA, INSTANCE);
  360.  
  361.   tlFrame = TimeLineWindow[xv_get(ip->controls, PANEL_CLIENT_DATA)];
  362.   switch (op) 
  363.   {
  364.    case MENU_DISPLAY:
  365.     break;
  366.    case MENU_DISPLAY_DONE:
  367.     break;
  368.    case MENU_NOTIFY:
  369.     if (strcmp(tlFrame->filename, "untitled") == 0)            /* No filename specified yet */
  370.       Browse(NULL, BrowseSave, (int) xv_get(ip->controls, PANEL_CLIENT_DATA), 
  371.          "#TimeLine Edit Document", "TimeLine Editor");
  372.     else 
  373.       Browse(tlFrame->filename, BrowseCheckSave, (int) xv_get(ip->controls, PANEL_CLIENT_DATA),
  374.          "#TimeLine Edit Document", "TimeLine Editor");
  375.     break;
  376.    case MENU_NOTIFY_DONE:
  377.     break;
  378.   }
  379.   return item;
  380. }
  381.  
  382. /*
  383.  * This function will read in a TimeLine document.  The following are
  384.  * the steps taken by this function:
  385.  * 1) Check if a filename has been specified.  If not, print error
  386.  *    message and return.
  387.  * 2) Check if the specified filename is called 'untitled', which is
  388.  *    not acceptable.  If so, print error message and return.
  389.  * 3) Check if the specified file exists.  If not, print error message
  390.  *    and return.
  391.  * 4) Check if there are unsaved changes in the current TimeLIne
  392.  *    document on display.  Let the user decide what to do (go on or cancel
  393.  *    the load file).
  394.  * 5) Check if the specified file is a TimeLine document file.  This *
  395.  *    is done by checking the header of the file, which should have the line
  396.  *    "#TimeLine Edit Document#" for a document generated by older
  397.  *    versions of TimeLine, or "#TimeLine Edit Document, Version 2#" for
  398.  *    newer versions of TimeLine, which generate synchronization hints.  If
  399.  *    the file is not a TimeLine document of some sort, print error message
  400.  *    and return.
  401.  * 6) Read in the names of the applications and create an instrument
  402.  *    list.  Compare this instrument list with a list obtained from the port
  403.  *    manager (in the OpenAppsInitialize function) to get the correct port
  404.  *    numbers for each app (if they are open).
  405.  * 7) Clear all the panel lists in the info pop-up windows.
  406.  * 8) We are now ready to read in the document.  Read in the
  407.  *    information for the pause markers, regions and notes respectively.
  408.  * 9) Call the repaint canvas procedure to draw the newly loaded
  409.  *    document on the display.
  410.  *10) Call the InitNotesInfo procedure to update the panel lists on
  411.  *    all the info pop-up windows that have been created.
  412.  */
  413.  
  414. int OpenHandler(char* filename, int TimeLineFrameNum)
  415. {
  416.   FILE*            fp;                        /* File handler to the edit file */
  417.   int            i, j;                        /* For loop variables */
  418.   int            tempint;                    /* Dummy integer variable */
  419.   int            readSyncHints = False;                /* Indicates if document should be parsed for sync hints */
  420.   char            buf[100];                    /* Used to store strings such as Error messages */
  421.   char            tempappName[64];                /* Stores the application name for an instrument */
  422.   char            tempLabel[MaxLabelLength + 8];
  423.   Instrument*        instrument;                    /* Pointer to an instrument node in the instrument list */
  424.   Note*            newNote;                    /* New note to be inserted in an instrument note list */
  425.   Pause*        newPause;
  426.   tlRegion*        newRegion;
  427.   MediaSegment*        ms;                        /* Media segment containing information about a note */
  428.   TimeLineFramePtr    tlFrame;
  429.   
  430.   tlFrame = TimeLineWindow[TimeLineFrameNum];
  431.   if (CheckforUntitled (filename))                    /* Check if filename is 'untitled' (unacceptable) */
  432.   {
  433.     AlertMessage(tlFrame, "'untitled' is not an acceptable filename.",
  434.          "Please type in a new one.", NULL);
  435.     return Error;
  436.   }
  437.   if (CheckChanges(LoadFile, tlFrame) == NOTICE_YES)            /* Check if unsaved changes exist in edit list */
  438.     return Error;
  439.   fp = fopen(filename, "r");                        /* Open the file for reading. */
  440.   fgets(buf, 37, fp);                            /* Check if file is a TimeLine edit file by reading header */
  441.   if ((strcmp(buf, "#TimeLine Edit Document#\n") != 0) &&
  442.       (strcmp(buf, "#TimeLine Edit Document, Version 2#\n") != 0))
  443.   {
  444.     AlertMessage(tlFrame, "This is not a TimeLine document.",
  445.          "Please select another document.", NULL);
  446.     fclose(fp);
  447.     return Error;
  448.   }
  449.   if (strcmp(buf, "#TimeLine Edit Document, Version 2#\n") == 0)    /* Is this a TimeLine document with synchronization hints? */
  450.   {                                    /* Yes, so no matter what, parse the lines that describe... */
  451.     readSyncHints = True;                        /* ...sync hints, even though the data might be invalid */
  452.     fscanf(fp, "#Sync Hints Available : %s\n", buf);            /* ...Does this document have valid sync info? */
  453.     if (strcmp(buf, "Yes") == 0)                    /* Yes, indicate that this function should parse the... */
  454.       tlFrame->syncHints = SyncHintsAvailable;                /* ...document for synchronization hints. */
  455.   }
  456.   else
  457.     tlFrame->syncHints = NoSyncHintsAvailable;
  458.   strcpy (tlFrame->filename, filename);
  459.   FreeInstrumentList(tlFrame);
  460.   fscanf(fp, "#Number of applications : %d\n", &tlFrame->numberOfApps);    /* Read in the # of apps used by this edit document */
  461.   for (i=0; i < tlFrame->numberOfApps; i++)                /* Create a new instrument list consisting of apps in file */
  462.   {
  463.     fscanf(fp, "#Name of application : %s\n", tempappName);
  464.     if (i == 0) 
  465.     {
  466.       tlFrame->instHead = (Instrument *) InstrumentNew(0, NULL, tlFrame, tempappName);
  467.       instrument = tlFrame->instHead;
  468.     }
  469.     else 
  470.     {
  471.       instrument->next = (Instrument *) InstrumentNew(i, NULL, tlFrame, tempappName);
  472.       instrument = instrument->next;
  473.     }
  474.   }
  475.   OpenAppsInitialize(tlFrame, 0);                    /* Match the applications with those currently open */
  476.   if (tlFrame->pauseEdit >= 0) 
  477.     xv_set(tlFrame->PausePopup->PauseList,                /* Deselect the selected entry on the panel list */
  478.        PANEL_LIST_SELECT, tlFrame->pauseEdit, 
  479.        FALSE, NULL);
  480.   FreePause(tlFrame);
  481.   fscanf(fp, "\n");
  482.   fscanf(fp, "********************************************************************\n");
  483.   fscanf(fp, "#Number of pauses : %d\n", &(tlFrame->numPause));
  484.   fscanf(fp, "********************************************************************\n");
  485.   for (i=0; i < tlFrame->numPause; i++) 
  486.   {
  487.     newPause = (Pause *) malloc (sizeof(Pause));
  488.     newPause->next = NULL;
  489.     fscanf(fp, "\n");
  490.     fscanf(fp, "#Pause %d\n", &tempint);
  491.     fscanf (fp, "Position : %d\n", &(newPause->position));
  492.     fscanf (fp, "Min, Sec : %d %d\n", &(newPause->min), &(newPause->sec));
  493.     InsertNewPause(tlFrame, newPause);
  494.   }
  495.   UpdatePauseList(tlFrame, 0);
  496.   
  497.   if (tlFrame->regionEdit >= 0) 
  498.     xv_set(tlFrame->RegionPopup->RegionList,                /* Deselect the selected entry on the panel list */
  499.        PANEL_LIST_SELECT, tlFrame->regionEdit, 
  500.        FALSE, NULL);
  501.   FreeRegion(tlFrame);
  502.   fscanf(fp, "\n");
  503.   fscanf(fp, "********************************************************************\n");
  504.   fscanf(fp, "#Number of regions : %d\n", &(tlFrame->numRegion));
  505.   fscanf(fp, "********************************************************************\n");
  506.   for (i=0; i < tlFrame->numRegion; i++) 
  507.   {
  508.     newRegion = (tlRegion *) malloc (sizeof(tlRegion));
  509.     newRegion->next = NULL;
  510.     fscanf(fp, "\n");
  511.     fscanf (fp, "#Region %d\n", &tempint);
  512.     fscanf (fp, "startX, endX : %d %d\n", &(newRegion->startX), &(newRegion->endX));
  513.     fscanf (fp, "startMin, endMin : %d %d\n", &(newRegion->startMin), &(newRegion->endMin));
  514.     fscanf (fp, "startSec, endSec : %d %d\n", &(newRegion->startSec), &(newRegion->endSec));
  515.     fgets(tempLabel, MaxLabelLength + 8, fp);
  516.     strcpy(newRegion->label, &tempLabel[8]);
  517.     newRegion->label[strlen(newRegion->label) - 1] = '\0';        /* Remove the newline character */
  518.     InsertNewRegion(tlFrame, newRegion);
  519.   }
  520.   UpdateRegionList(tlFrame);
  521.   if (tlFrame->noteInstrument != NULL) 
  522.   {
  523.     if (tlFrame->noteInstrument->infoNote != NULL)            /* Deselect the note on the panel list */
  524.     {
  525.       xv_set(tlFrame->noteInstrument->editInfo->NoteInfoList,
  526.          PANEL_LIST_SELECT, tlFrame->noteInstrument->selectedInfoNote,
  527.          FALSE, NULL);
  528.     }
  529.   }
  530.   ClearAllNotes(tlFrame);                    /* Clear the notes for all the instruments */
  531.   instrument = tlFrame->instHead;
  532.   for (i=0; i < tlFrame->numberOfApps; i++)                /* Now load the notes info for each instrument */
  533.   {
  534.     fscanf(fp, "\n");
  535.     fscanf(fp, "********************************************************************\n");
  536.     fscanf(fp, "#Name of application : %s\n", tempappName);        /* Read in the app name and check for it in the app list */
  537.     fscanf(fp, "#Number of notes : %d\n", &(instrument->numnotes)); /* Read in the number of notes for this application */
  538.     fscanf(fp, "********************************************************************\n");
  539.     for (j=0; j < instrument->numnotes; j++)                /* Add the notes in the notes list for this application */
  540.     {
  541.       ms = (MediaSegment *) malloc (sizeof(MediaSegment));        /* Create a new media segment */
  542.       ms->documentName = (char *) malloc(MAXPATHLEN);
  543.       ms->selection = (MAESelection*) malloc(sizeof(MAESelection));
  544.       newNote = (Note *) malloc (sizeof(Note));            /* Create a new note */
  545.       newNote->ms = ms;
  546.       newNote->next = NULL;
  547.       fscanf(fp, "\n");
  548.       fscanf(fp, "#Note %d\n", &tempint);                /* Read in the values for the note from the file */
  549.       fscanf(fp, "Display parameters : %d %d\n", &(newNote->start), &(newNote->end));
  550.       fscanf(fp, "Document name : %s\n", ms->documentName);
  551.       fscanf(fp, "Selection parameters : %d %d %d\n", 
  552.          &(ms->selection->start),
  553.          &(ms->selection->end),
  554.          &(ms->selection->duration));                /* Stored in milliseconds */
  555.       ms->duration = ms->selection->duration / 500;            /* Stored in half seconds */
  556.       ms->selection->offset = 0;                    /* Initialize offset to zero */
  557.       CalculateNoteTime(newNote);                    /* Calculate the min and sec representations of the... */
  558.                                     /* ...start and end of the note */
  559.       if (readSyncHints == True)                    /* Does this document store synchronization hints? */
  560.       {                                    /* Yes, read the estimated setup time into this note's... */
  561.     fscanf(fp, "Estimated Setup Time : %d milliseconds\n",        /* ...data structure. */
  562.            &(ms->setupTime));
  563.       }
  564.       else
  565.     ms->setupTime = 0;
  566.       fgets(tempLabel, MaxLabelLength + 8, fp);
  567.       strcpy(ms->selection->label, &tempLabel[8]);
  568.       (ms->selection->label)[strlen(ms->selection->label) - 1] = '\0';
  569.       InsertNewNote (instrument, newNote, tlFrame);            /* Insert new note into the Notes List of that application */
  570.     }
  571.     instrument = instrument->next;
  572.   }
  573.   fclose(fp);
  574.   instrument = tlFrame->instHead;                    /* Load panel list of info pop-up windows with new Note info */
  575.   while (instrument != NULL) 
  576.   {
  577.     InitNotesInfo(instrument, 1, tlFrame);
  578.     instrument = instrument->next;
  579.   }
  580.   tlFrame->change = 0;
  581.   UpdateHeader(tlFrame, 0);
  582.   DrawPlaybackHead(-1, tlFrame);
  583.   tlFrame->canvasStart = 0;
  584.   ScrollToFirstQuarter(tlFrame, 0, 1);                    /* Scroll to make the start of the document visible */
  585.   AppCanvasRepaintHandler(tlFrame->TimeLine_window->AppCanvas, tlFrame->paintWinApp, 
  586.                tlFrame->dpyApp, tlFrame->xidApp, NULL);
  587.   return OK;
  588. }                                    /* end function OpenHandler */
  589.  
  590.  
  591. /*
  592.  * The Browse function in Browse.c will call this function.  This
  593.  * function will save the current TimeLine document in a file.  The
  594.  * following are the steps taken by this function.
  595.  * 1) Check if a filename has been specified.  If not, print error
  596.  *    message and return.
  597.  * 2) Check if the specified filename is called 'untitled', which is not
  598.  *    acceptable.  If so, print Error message and return.
  599.  * 3) Check if the specified file can be opened.  If the file already
  600.  *    exists, check if it is a TimeLine document file by checking the header.
  601.  *    Print a message warning the user that the file already exists and give
  602.  *    the option to go ahead or abort the operation.
  603.  * 4) Now, open the file and write the data about the current TimeLine
  604.  *    document in it.  Information is written about the pause markers,
  605.  *    annotated regions and the notes respectively.  Only applications with
  606.  *    notes will be saved.
  607.  */
  608. int SaveHandler(char* filename, int TimeLineFrameNum)
  609. {
  610.   FILE*            fp;                        /* File handler to the edit file */
  611.   struct stat        stbuf;
  612.   int            count;                        /* Count of the number of notes in an instrument */
  613.   char            buf[100];                    /* Used to store strings such as Error messages */
  614.   Instrument*        instrument;                    /* Pointer to an instrument node in the instrument list */
  615.   Note*            currentNote;                    /* Pointer to the current note being read */
  616.   Pause*        currentPause;                    /* Pointer to the current pause marker being read */
  617.   tlRegion*        currentRegion;                    /* Pointer to the current region being read */
  618.   TimeLineFramePtr    tlFrame;
  619.   
  620.   tlFrame = TimeLineWindow[TimeLineFrameNum];
  621.   if (CheckforUntitled (filename))                    /* Check if filename is 'untitled' (unacceptable) */
  622.   {
  623.     AlertMessage(tlFrame, "'untitled' is not an acceptable filename.",
  624.          "Please type in a new one.", NULL);
  625.     return Error;
  626.   }
  627.   if (stat(filename, &stbuf) == 0)                    /* Check if the file can be opened properly */
  628.   {
  629.     fp = fopen(filename, "r");
  630.     fgets(buf, 37, fp);                            /* Get the header of the file */
  631.     fclose(fp);
  632.   if ((strcmp(buf, "#TimeLine Edit Document#\n") != 0) &&        /* Check if it is a TimeLine Edit file */
  633.       (strcmp(buf, "#TimeLine Edit Document, Version 2#\n") != 0))
  634.     sprintf(buf, "This is not a TimeLine edit document.");
  635.     else 
  636.       sprintf(buf, "This TimeLine edit document exists.");
  637.     if (notice_prompt(tlFrame->TimeLine_window->window, NULL,        /* Prompts the user if the file is to be overwritten */
  638.               NOTICE_MESSAGE_STRINGS,
  639.               buf, "Do you wish to overwrite it?", NULL,
  640.               NOTICE_BUTTON_NO,       "Yes",
  641.               NOTICE_BUTTON_YES,      "No",
  642.               NULL) == NOTICE_YES)
  643.       return Error;
  644.   }
  645.   fp = fopen(filename, "w");                        /* Open the file for writing. */
  646.   strcpy(tlFrame->filename, filename);
  647.   fprintf(fp, "#TimeLine Edit Document, Version 2#\n");            /* Write the header. */
  648.   if (tlFrame->syncHints == SyncHintsAvailable)                /* Indicate whether synchronization hints are available... */
  649.     fprintf(fp, "#Sync Hints Available : Yes\n");            /* ...for this document. */
  650.   else
  651.     fprintf(fp, "#Sync Hints Available : No\n");
  652.   count = 0;
  653.   instrument = tlFrame->instHead;
  654.   while (instrument != NULL)                        /* Count how many applications there are that contain notes */
  655.   {
  656.     if (instrument->numnotes > 0) 
  657.       count ++;
  658.     instrument = instrument->next;
  659.   }
  660.   fprintf(fp, "#Number of applications : %d\n", count);            /* Write the number of applications that this document needs */
  661.   instrument = tlFrame->instHead;                    /* Write the names of the apps required first.  This is... */
  662.                                     /* ...to facilitate checking later when loading... */
  663.                                     /* ...a file.  We can straight away find out if all the... */
  664.                                     /* ...required apps are open by reading the first few... */
  665.                                     /* ...lines of the file. */
  666.   while (instrument != NULL) 
  667.   {
  668.     if (instrument->numnotes > 0) 
  669.       fprintf(fp, "#Name of application : %s\n", instrument->port->appName);
  670.     instrument = instrument->next;
  671.   }
  672.   count = 1;
  673.   currentPause = tlFrame->pauseHead;
  674.   fprintf(fp, "\n");
  675.   fprintf(fp, "********************************************************************\n");
  676.   fprintf(fp, "#Number of pauses : %d\n", tlFrame->numPause);        /* Write the number of pauses for this application */
  677.   fprintf(fp, "********************************************************************\n");
  678.   while (currentPause != NULL) 
  679.   {
  680.     fprintf(fp, "\n");
  681.     fprintf (fp, "#Pause %d\n", count);
  682.     fprintf (fp, "Position : %d\n", currentPause->position);
  683.     fprintf (fp, "Min, Sec : %d %d\n", currentPause->min, currentPause->sec);
  684.     count ++;
  685.     currentPause = currentPause->next;
  686.   }
  687.   count = 1;
  688.   currentRegion = tlFrame->regionHead;
  689.   fprintf(fp, "\n");
  690.   fprintf(fp, "********************************************************************\n");
  691.   fprintf(fp, "#Number of regions : %d\n", tlFrame->numRegion);        /* Write the number of regions for this application */
  692.   fprintf(fp, "********************************************************************\n");
  693.   while (currentRegion != NULL) 
  694.   {
  695.     fprintf(fp, "\n");
  696.     fprintf (fp, "#Region %d\n", count);
  697.     fprintf (fp, "startX, endX : %d %d\n", currentRegion->startX, currentRegion->endX);
  698.     fprintf (fp, "startMin, endMin : %d %d\n", currentRegion->startMin, currentRegion->endMin);
  699.     fprintf (fp, "startSec, endSec : %d %d\n", currentRegion->startSec, currentRegion->endSec);
  700.     fprintf(fp, "Label : %s\n", currentRegion->label);
  701.     count ++;
  702.     currentRegion = currentRegion->next;
  703.   }
  704.   instrument = tlFrame->instHead;                    /* For each instrument, write the info required for... */
  705.                                     /* ...loading later. This information includes the name... */
  706.                                     /* ...of the application, the number of notes in each... */
  707.                                     /* ...application, media segment information for each... */
  708.                                     /* ...note, and where each note is displayed on the canvas. */
  709.   while (instrument != NULL) 
  710.   {
  711.     if (instrument->numnotes > 0) 
  712.     {
  713.       fprintf(fp, "\n");
  714.       fprintf(fp, "********************************************************************\n");
  715.       fprintf(fp, "#Name of application : %s\n", instrument->port->appName); /* Write the name of the application */
  716.       fprintf(fp, "#Number of notes : %d\n", instrument->numnotes); /* Write the number of notes for this application */
  717.       fprintf(fp, "********************************************************************\n");
  718.       currentNote = instrument->firstNote;                /* Now write the information for each note */
  719.       count = 1;
  720.       while (currentNote != NULL) 
  721.       {
  722.     fprintf(fp, "\n");
  723.     fprintf (fp, "#Note %d\n", count);
  724.     fprintf (fp, "Display parameters : %d %d\n", currentNote->start, 
  725.          currentNote->end);
  726.     fprintf (fp, "Document name : %s\n",  currentNote->ms->documentName);
  727.     fprintf (fp, "Selection parameters : %d %d %d\n", 
  728.          currentNote->ms->selection->start,
  729.          currentNote->ms->selection->end,
  730.          currentNote->ms->selection->duration);
  731.     fprintf(fp, "Estimated Setup Time : %d milliseconds\n",
  732.         currentNote->ms->setupTime);
  733.     fprintf(fp, "Label : %s\n", currentNote->ms->selection->label);
  734.     currentNote = currentNote->next;
  735.     count ++;
  736.       }
  737.     }
  738.     instrument = instrument->next;
  739.   }
  740.   fclose (fp);
  741.   tlFrame->change = 0;                            /* Reset the change flag */
  742.   UpdateHeader(tlFrame, 0);
  743.   return OK;
  744. }                                    /* end function SaveHandler */
  745.  
  746.  
  747. /*
  748.  * Menu handler for `DocumentMenu (Save as ...)'.
  749.  */
  750. Menu_item SaveAsFileHandler(Menu_item        item,
  751.                 Menu_generate    op)
  752. {
  753.   TimeLine_window_objects * ip = (TimeLine_window_objects *) xv_get(item, XV_KEY_DATA, INSTANCE);
  754.  
  755.   switch (op) 
  756.   {
  757.    case MENU_DISPLAY:
  758.     break;
  759.    case MENU_DISPLAY_DONE:
  760.     break;
  761.    case MENU_NOTIFY:
  762.     Browse(NULL, BrowseSave, (int) xv_get(ip->controls, PANEL_CLIENT_DATA), 
  763.        "#TimeLine Edit Document", "TimeLine Editor");
  764.     break;
  765.    case MENU_NOTIFY_DONE:
  766.     break;
  767.   }
  768.   return item;
  769. }
  770.  
  771. /*
  772.  * Menu handler for `DocumentMenu (Quit)'.
  773.  * This function will attempt to destroy a frame.  Because the notify interpose destroy function has been specified, the QuitNotify function will be
  774.  * called to check if the frame is to be destroyed.
  775.  */
  776. Menu_item QuitHandler(item, op)
  777.      Menu_item    item;
  778.      Menu_generate    op;
  779. {
  780.   int whichWindow;
  781.   TimeLineFramePtr tlFrame;
  782.   TimeLine_window_objects * ip = (TimeLine_window_objects *) xv_get(item, XV_KEY_DATA, INSTANCE);
  783.  
  784.   whichWindow = xv_get(ip->controls, PANEL_CLIENT_DATA);
  785.   tlFrame = TimeLineWindow[whichWindow];
  786.   switch (op) 
  787.   {
  788.    case MENU_DISPLAY:
  789.     break;
  790.    case MENU_DISPLAY_DONE:
  791.     break;
  792.    case MENU_NOTIFY:
  793.     xv_destroy_safe(tlFrame->TimeLine_window->window);            /* Destroy the application */
  794.     break;
  795.    case MENU_NOTIFY_DONE:
  796.     break;
  797.   }
  798.   return item;
  799. }
  800.  
  801. /*
  802.  * Menu handler for `DocumentMenu (New)'.
  803.  * This function will first check through the array indicating the status of a TimeLine Window to see which is available for creation.
  804.  * It will only create a new window if there is one free.
  805.  */
  806. Menu_item NewHandler(item, op)
  807.      Menu_item    item;
  808.      Menu_generate    op;
  809. {
  810.   int whichWindow, count;
  811.   
  812.   switch (op) 
  813.   {
  814.    case MENU_DISPLAY:
  815.     break;
  816.    case MENU_DISPLAY_DONE:
  817.     break;
  818.    case MENU_NOTIFY:
  819.     count = 1;
  820.     whichWindow = MaxWindows + 1;
  821.     while (count <= MaxWindows) 
  822.     {
  823.       if (WindowFree[count] == 0)                    /* Check to see which window is free */
  824.       {
  825.     whichWindow = count;
  826.     count = MaxWindows;
  827.       }
  828.       count ++;
  829.     }
  830.     if (whichWindow <= MaxWindows)                    /* One window is free.  Create a new TimeLine */
  831.       TimeLineInit(TimeLineWindow[whichWindow], whichWindow);
  832.     break;
  833.    case MENU_NOTIFY_DONE:
  834.     break;
  835.   }
  836.   return item;
  837. }
  838.  
  839. /*
  840.  * Menu handler for `DocumentMenu (About TimeLine Editor ...)'.
  841.  * This function pops up the Info window.
  842.  */
  843. Menu_item AboutHandler(item, op)
  844.      Menu_item    item;
  845.      Menu_generate    op;
  846. {
  847.   TimeLineFramePtr tlFrame;
  848.   TimeLine_window_objects * ip = (TimeLine_window_objects *) xv_get(item, XV_KEY_DATA, INSTANCE);
  849.  
  850.   tlFrame = TimeLineWindow[xv_get(ip->controls, PANEL_CLIENT_DATA)];
  851.   switch (op) 
  852.   {
  853.    case MENU_DISPLAY:
  854.     break;
  855.    case MENU_DISPLAY_DONE:
  856.     break;
  857.    case MENU_NOTIFY:
  858.     xv_set(tlFrame->InfoPopup->InfoPopup, FRAME_CMD_PUSHPIN_IN, TRUE, NULL);
  859.     xv_set(tlFrame->InfoPopup->InfoPopup, XV_SHOW, TRUE, NULL);
  860.     break;
  861.    case MENU_NOTIFY_DONE:
  862.     break;
  863.   }
  864.   return item;
  865. }
  866.  
  867. /*
  868.  * Notify callback function for `closeInfoButton'.
  869.  * This function will close the Info popup window.
  870.  */
  871. void CloseInfoPopup(item, event)
  872.      Panel_item    item;
  873.      Event        *event;
  874. {
  875.   Info_InfoPopup_objects    *ip = (Info_InfoPopup_objects *) xv_get(item, XV_KEY_DATA, INSTANCE);
  876.  
  877.   xv_set(ip->InfoPopup, FRAME_CMD_PUSHPIN_IN, FALSE, NULL);
  878.   xv_set(ip->InfoPopup, XV_SHOW, FALSE, NULL);
  879. }
  880.  
  881. /*
  882.  * Menu handler for `DocumentMenu (Close)'.
  883.  * This function will close the currently loaded file (if any), reset the filename to "untitled" and clear the whole canvas.
  884.  * If multiple TimeLine windows are open, instead of closing the file, the whole TimeLine frame will be destroyed.
  885.  */
  886. Menu_item CloseHandler(item, op)
  887.      Menu_item    item;
  888.      Menu_generate    op;
  889. {
  890.   TimeLineFramePtr tlFrame;
  891.   TimeLine_window_objects * ip = (TimeLine_window_objects *) xv_get(item, XV_KEY_DATA, INSTANCE);
  892.  
  893.   tlFrame = TimeLineWindow[xv_get(ip->controls, PANEL_CLIENT_DATA)];
  894.   switch (op) 
  895.   {
  896.    case MENU_DISPLAY:
  897.     break;
  898.    case MENU_DISPLAY_DONE:
  899.     break;
  900.    case MENU_NOTIFY:
  901.     if (numberOfWindows == 1) 
  902.     {
  903.       if (CheckChanges(CloseFile, tlFrame) == NOTICE_YES)        /* Check if unsaved changes exist in edit list */
  904.     return item;
  905.       tlFrame->change = 0;
  906.       ClearAllHandler(item, MENU_NOTIFY);
  907.       strcpy(tlFrame->filename, "untitled");
  908.       tlFrame->change = 0;
  909.       UpdateHeader(tlFrame, 0);
  910.       ScrollToFirstQuarter(tlFrame, 0, 1);
  911.     }
  912.     else 
  913.     {
  914.       quitAll = 0;                            /* Destroy this window */
  915.       xv_destroy_safe(tlFrame->TimeLine_window->window);
  916.     }
  917.     break;
  918.    case MENU_NOTIFY_DONE:
  919.     break;
  920.   }
  921.   return item;
  922. }
  923.